package jnpf.engine.custom.handler.condition;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import jnpf.base.UserInfo;
import jnpf.engine.model.flowengine.shuntjson.childnode.GroupsModel;
import jnpf.engine.model.flowengine.shuntjson.childnode.ProperCond;
import jnpf.engine.model.flowengine.shuntjson.childnode.Properties;
import jnpf.engine.model.flowtask.FlowConditionModel;
import jnpf.engine.util.FlowContextHolder;
import jnpf.engine.util.SpringContextHolder;
import jnpf.permission.entity.UserEntity;
import jnpf.permission.service.UserService;
import jnpf.util.JsonUtil;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.model.Process;
import org.flowable.engine.delegate.DelegateExecution;
import org.flowable.engine.impl.Condition;

import javax.script.ScriptEngine;
import java.util.*;

import static jnpf.engine.util.BpmnModelUtils.getAttributeValueByTaskDefinitionKey;
import static jnpf.engine.util.BpmnModelUtils.getBpmnModelMainProcess;
import static jnpf.engine.util.EvalUtils.*;

@Slf4j
public class NashornCondition implements Condition {
	private static final long serialVersionUID = -5577703954744892854L;
	private String attributeValue = "";

	public NashornCondition(String attributeValue) {
		this.attributeValue = attributeValue;
	}
	@Override
	public boolean evaluate(String sequenceFlowId, DelegateExecution execution) {
		Process bpmnModelMainProcess = getBpmnModelMainProcess(execution.getProcessDefinitionId());
		UserProvider userProvider = SpringContextHolder.getBean(UserProvider.class);
		UserService userService = SpringContextHolder.getBean(UserService.class);
		ScriptEngine scriptEngine = SpringContextHolder.getBean(ScriptEngine.class);
		String sequenceFlowStr = getAttributeValueByTaskDefinitionKey(bpmnModelMainProcess, sequenceFlowId, "sequenceFlow");
		Properties properties = JSONObject.parseObject(sequenceFlowStr, new TypeReference<Properties>() {
		});
		List<ProperCond> conditionList = properties.getConditions();
		FlowConditionModel conditionModel=new FlowConditionModel();
		UserInfo userInfo = userProvider.get();
		conditionModel.setUserInfo(userInfo);
		UserEntity userEntity=null;
		if(userInfo==null){
			userEntity = userService.getInfo("admin");
		}
		else{
			userEntity=userService.getInfo(userInfo.getUserId());
		}
		conditionModel.setUserEntity(userEntity);

		Map<String,Object> variablesMap = new HashMap<>();
		Map<String, Object> variables = execution.getVariables();
		variablesMap.putAll(variables);
		conditionModel.setVariablesMap(variablesMap);
		String objectToString = JsonUtil.getObjectToString(variablesMap);
		conditionModel.setData(objectToString);
		boolean flag = false;

		Map<String, Map<String, Object>> nodeFormData = FlowContextHolder.getNodeFormData();
		Map<String,Object> dataMap = new HashMap<>();
		Set<String> strings = nodeFormData.keySet();
		for (String string : strings) {
			Map<String, Object> map = nodeFormData.get(string);
			dataMap.putAll(map);
		}
		variablesMap.putAll(dataMap);


		List<ProperCond> conditions = properties.getConditions();
		String matchLogic = properties.getMatchLogic();

		List<String> expressionAll = new ArrayList<>();
		StringBuilder condition = new StringBuilder();
		for (int k = 0; k < conditionList.size(); k++) {
			StringBuilder expression = new StringBuilder();
			expression.append("(");
			ProperCond properCond = conditionList.get(k);
			String logic = properCond.getLogic();
			List<GroupsModel> groups = properCond.getGroups();
			for (int i = 0; i < groups.size(); i++) {
				GroupsModel groupsModel = groups.get(i);
				String contain = "!=-1";
				String field = groupsModel.getField();
				String jnpfKey = groupsModel.getJnpfKey();
				int fieldType = groupsModel.getFieldType();
				Object form = fieldType == 1 ? formValue(conditionModel, jnpfKey, variablesMap.get(field)) : formula(groupsModel, variablesMap);
				Object formValue = form;
				String symbol = groupsModel.getSymbol();
				boolean include = ("like".equals(symbol) || "notLike".equals(symbol));
				if ("<>".equals(symbol)) {
					symbol = "!=";
				}
				int fieldValueType = groupsModel.getFieldValueType();
				String valueJnpfKey = StringUtil.isNotEmpty(groupsModel.getFieldValueJnpfKey()) ? groupsModel.getFieldValueJnpfKey() : jnpfKey;
				Object filedData = groupsModel.getFieldValue();
				Object value = fieldValueType == 2 ? filedValue(conditionModel, filedData, valueJnpfKey, form) : filedData(conditionModel, filedData, valueJnpfKey, form);
				Object fieldValue = value;
				String pression = formValue + symbol + fieldValue;
				if (include) {
					if ("notLike".equals(symbol)) {
						contain = "==-1";
					}
					symbol = ".indexOf";
					formValue = formValue == null ? "''" : formValue;
					pression = formValue + ".toString()" + symbol + "(" + fieldValue + ")" + contain;
				}
				expression.append(pression);
				if (!StringUtils.isEmpty(logic) && i != groups.size() - 1) {
					expression.append(" " + search(logic) + " ");
				}
			}
			expression.append(")");
			expressionAll.add(expression.toString());
		}
		for (int i = 0; i < expressionAll.size(); i++) {
			String script = expressionAll.get(i);
			String search = i != expressionAll.size() - 1 ? search(matchLogic) : "";
			condition.append(script + " " + search + " ");
		}



		try {
			flag = (Boolean) scriptEngine.eval(condition.toString());
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		return flag;
	}



}
